#ifndef __FREECAMERA_H__
#define __FREECAMERA_H__

#include "../geom/Point3D.h"
#include "../geom/Vector3D.h"
#include "../algebra/Matrix.h"
#include "../geom/Frustum.h"

namespace glutil
{
	/** OpenGL camera that can move freely through the world */
	class FreeCamera
	{
		public:
			/** Constructor
			  @param pos Camera position
			  @param viewVector The direction the camera is looking at
			  @param FOV Field of view of the camera */
			FreeCamera(geom::Point3D pos, geom::Vector3D viewVector, float FOV) : m_FOV(FOV) 
			{
				for(int i=0;i<3;++i)
				{
					m_position[i] = pos.v[i];
					m_viewDir[i] = viewVector.dv[i];
				}
				
				m_up[0] = 0, m_up[1] = 1, m_up[2] = 0;
			}
			/** Moves the camera by the given vector */
			void move(geom::Vector3D distance);
			/** Moves the camera forward the given amount*/
			void advance(float amount);
			/** Moves the camera to the left by the given amount*/
			void strafeLeft(float amount);
			/** Moves the camera to the right by the given amount */
			void strafeRight(float amount);
			/** Moves the camera up by the given amount*/
			void moveUp(float amount);

			/** Sets the camera aspect ratio (width/height)*/
			void setAspectRatio(float ratio);
			/** Rotates the camera the given amount, as rotated when moving the mouse */
			void mouseLookTurn(float dx, float dy);
			/** Changes the viewVector to make the camera look at the given point */
			void lookAt(geom::Point3D pos);

			/** Gets the current camera frustum */
			geom::Frustum getFrustum() const;
			/** Gets the camera position */
			geom::Point3D position() const { return geom::Point3D (&(m_position[0]));}
			/** Gets the direction the camera is looking */
			geom::Vector3D viewVector() const { return geom::Vector3D (&(m_viewDir[0]));}
			/** Gets the transformation matrix for this camera (in a format directly usable by OpenGL)*/
			algebra::Matrix4f getTransformationMatrix();

			/** Gets the camera field of view */
			float FOV() const {return m_FOV;}

			/** Sets the camera field of view */
			void setFOV(float FOV){m_FOV = FOV;}
			/** Sets this camera transformation as the current OpenGL transformation*/
			void setAsGLCamera();

		private:

			algebra::Vector3f m_viewDir;
			algebra::Vector3f m_position;
			algebra::Vector3f m_up;

			float m_FOV;
			float m_ratio;
	};
}

#endif
